#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <algorithm>
#include <sys/select.h>
#include "include/TcpSocket.hpp"
#include "include/Log.hpp"

const static int default_port = 9090;
const static int max_array = sizeof(fd_set)*8;

class SelectServer
{
public:
    SelectServer(int port = default_port): _port(port), _listen_sock(new TcpSocket()), _isRunning(false)
    {
        _listen_sock->createListenSocket(_port);
        for(int i = 0; i < max_array; i++)
        {
            _rfds_array[i] = nullptr;
        }
        _rfds_array[0] = _listen_sock.get(); //unique_ptr的原始指针
    }

    void start()
    {
        _isRunning = true;
        while(_isRunning)
        {
            // 所有fd，都要先交给select等，获取新连接，相当于读事件，链接到来，数据就绪

            fd_set rfds; //放在循环内部，下一轮循环重设
            FD_ZERO(&rfds);
            int maxFdAddOne = -1;
            for(int i = 0; i < max_array; i++)
            {
                if(_rfds_array[i] != nullptr)
                {
                    FD_SET(_rfds_array[i]->getSocketFd(), &rfds);
                    maxFdAddOne = std::max(maxFdAddOne, _rfds_array[i]->getSocketFd()+1);
                }
            }

            struct timeval timeout = {5, 0};
            int n = select(maxFdAddOne, &rfds, nullptr, nullptr, &timeout);
            if(n == 0) 
            {
                log.message(INFO, "select timeout...");
            }
            else if(n < 0)
            {
                log.message(ERROR, "select error...");
            }
            else
            {
                eventHandler(rfds); //事件派发
                log.message(INFO, "select success...");
            }
        }
        _isRunning = false;
    }

    void stop()
    {
        _isRunning = false;
    }

    ~SelectServer()
    {}
private:
    void eventHandler(fd_set& rfds)
    {
        for(int i = 0; i < max_array; i++) //遍历fd数组
        {
            if(_rfds_array[i] != nullptr) //判断合法性
            {
                if(FD_ISSET(_rfds_array[i]->getSocketFd(), &rfds)) //关心的fd在select就绪集合中，读事件就绪（连接到来，数据到来）
                {
                    if(_rfds_array[i]->getSocketFd() == _listen_sock->getSocketFd()) //连接到来
                    {
                        log.message(INFO, "get a new link");
                        std::string clientIp;
                        uint16_t clientPort;
                        Socket* connect_sock = _listen_sock->accept(&clientIp, &clientPort);
                        if(connect_sock == nullptr)
                        {
                            log.message(ERROR, "accept error...");
                            continue;
                        }
                        log.message(INFO, "[%s:%d], fd:%d, new client is connected...", clientIp.c_str(), clientPort, connect_sock->getSocketFd());

                        // 连接建立后，若想读写，仍需先让select等，_rfds_array负责管理已连接的fd
                        bool canAdd = false;
                        for(int pos = 0; pos < max_array; pos++) 
                        {
                            if(_rfds_array[pos] == nullptr)
                            {
                                _rfds_array[pos] = connect_sock;
                                canAdd = true;
                                break;
                            }
                        }
                        if(canAdd = false)
                        {
                            delete connect_sock;
                            log.message(WARN, "fd set is full...");
                        }
                    }
                    else //数据到来
                    {
                        char buffer[1024];
                        ssize_t n = read(_rfds_array[i]->getSocketFd(), buffer, sizeof(buffer)-1);
                        if(n > 0)
                        {
                            buffer[n] = '\0';
                            std::cout << "echo# " << buffer << std::endl;
                        }
                        else
                        {
                            delete _rfds_array[i];
                            _rfds_array[i] = nullptr;
                        }
                    }
                }
            }
        }
    }
private:
    int _port;
    std::unique_ptr<Socket> _listen_sock;
    bool _isRunning;
    Socket* _rfds_array[max_array]; //fd_set大小有上限，需要手动维护一个数组管理需要select关心的fd
};